address 0x0:

// This module is used for emitting events into the event_store.
module Event {
    use 0x0.Transaction;
    use 0x0.AddressUtil;
    use 0x0.BytearrayUtil;
    use 0x0.Hash;
    use 0x0.U64Util;

    // A resource representing the counter used to generate uniqueness under each account. There won't be destructor for
    // this resource to guarantee the uniqueness of the generated handle.
    resource struct HandleIdGenerator {
        // A monotonically increasing counter
        count: u64,
    }

    // A handle for a event such that:
    // 1. Other modules can emit event to this handle.
    // 2. Storage can use this handle to prove the total number of events that happened in the past.
    resource struct Handle<T: copyable> {
        // Total number of events emitted to this event stream.
        count: u64,
        // A globally unique ID for this event stream.
        guid: bytearray,
    }

    // Derive a fresh unique id by using sender's HandleIdGenerator. The generated bytearray is indeed unique because it
    // was derived from the hash(sender's HandleIdGenerator || sender_address). This module guarantees that the
    // HandleIdGenerator is only going to be monotonically increased and there's no way to revert it or destroy it. Thus
    // such counter is going to give distinct value for each of the new event stream under each sender. And since we
    // hash it with the sender's address, the result is guaranteed to be globally unique.
    fresh_guid(): bytearray acquires HandleIdGenerator {
        let sender = Transaction.sender();

        if (!exists<HandleIdGenerator>(sender))
            move_to_sender<HandleIdGenerator>(HandleIdGenerator { count: 0 });

        let generator = borrow_global_mut<HandleIdGenerator>(sender);

        let count_bytes = U64Util.u64_to_bytes(generator.count);
        generator.count = generator.count + 1;
        let sender_bytes = AddressUtil.address_to_bytes(sender);

        // HandleIdGenerator goes first just in case we want to extend address in the future.
        Hash.sha3_256(BytearrayUtil.bytearray_concat(count_bytes, sender_bytes))
    }

    // Use the sender's HandleIdGenerator to generate a unique event handle that one can emit an event to.
    public new_event_handle<T: copyable>(): Handle<T> acquires HandleIdGenerator {
        Handle { count: 0, guid: fresh_guid() }
    }

    // Emit an event with payload `msg` by using handle's key and counter. Will change the payload from bytearray to a
    // generic type parameter once we have generics.
    public emit_event<T: copyable>(handle: &mut Handle<T>, msg: T) {
        write_to_event_store<T>(handle.guid, handle.count, msg);
        handle.count = handle.count + 1
    }

    // Native procedure that writes to the actual event stream in Event store
    // This will replace the "native" portion of EmitEvent bytecode
    native write_to_event_store<T: copyable>(guid: bytearray, count: u64, msg: T);

    // Destroy a unique handle.
    public destroy<T: copyable>(handle: Handle<T>) {
        let Handle { count: _, guid: _ } = handle;
    }

    // TODO: We might want getters for reading the counter / id given a reference to a handle.
}
